#include "display.h"
#include "display_lib.h"
#include "../core/uart/uart.h"
#include <Wire.h>

TwoWire screen = TwoWire(0);

millis_t _display::update_screen = 0;

static uint32_t _buffer_size = 0;

static uint8_t _buffer[2048] = {0};

bool _display::init = false;

#define OLED_CMD 0  // 写命令
#define OLED_DATA 1 // 写数据

inline void OLED_RX_buf(uint8_t data)
{
    _buffer[_buffer_size] = data;
    _buffer_size++;
}

// WRITE
inline void OLED_WR_Byte(uint8_t dat, uint8_t mode)
{
    screen.beginTransmission(0x3c);
    if (mode)
    {
        screen.write(0x40);
    }
    else
    {
        screen.write(0x00);
    }
    screen.write(dat); // sends one byte
    screen.endTransmission();
}
inline void OLED_WR_Buf(uint8_t dat, uint8_t mode)
{   
    OLED_RX_buf(0x3c);
    if (mode)
    {
        OLED_RX_buf(0x40);
    }
    else
    {
        OLED_RX_buf(0x00);
    }
    OLED_RX_buf(dat); // sends one byte
}
// 反色显示
inline void OLED_ColorTurn(uint8_t i)
{
    if (!i)
        OLED_WR_Byte(0xA6, OLED_CMD); // 正常显示
    else
        OLED_WR_Byte(0xA7, OLED_CMD); // 反色显示
}
// 设置坐标
inline void OLED_Set_Pos(uint8_t x, uint8_t y)
{
    x += 26; // OFFSET
    OLED_WR_Byte(0xb0 + y, OLED_CMD);
    OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
    OLED_WR_Byte((x & 0x0f), OLED_CMD);
}
// 翻转显示
inline void OLED_DisplayTurn(uint8_t i)
{
    if (i == 0)
    {
        OLED_WR_Byte(0xC8, OLED_CMD); // 正常显示
        OLED_WR_Byte(0xA1, OLED_CMD);
    }
    if (i == 1)
    {
        OLED_WR_Byte(0xC0, OLED_CMD); // 反转显示
        OLED_WR_Byte(0xA0, OLED_CMD);
    }
}
// 开启OLED显示
inline void OLED_Display_On(void)
{
    OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC命令
    OLED_WR_Byte(0X14, OLED_CMD); // DCDC ON
    OLED_WR_Byte(0XAF, OLED_CMD); // DISPLAY ON
}
// 关闭OLED显示
inline void OLED_Display_Off(void)
{
    OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC命令
    OLED_WR_Byte(0X10, OLED_CMD); // DCDC OFF
    OLED_WR_Byte(0XAE, OLED_CMD); // DISPLAY OFF
}
// 清屏
inline void OLED_Clear(void)
{
    for (uint32_t buf_size = 0; buf_size < _buffer_size; buf_size++)
    {
        _buffer[buf_size] = 0;
    }
    _buffer_size = 0;

    uint8_t i, n;
    for (i = 0; i < 5; i++)
    {
        OLED_WR_Byte(0xb0 + i, OLED_CMD); // 设置页地址（0~7）
        OLED_WR_Byte(0x0c, OLED_CMD);     // 设置显示位置—列低地址
        OLED_WR_Byte(0x11, OLED_CMD);     // 设置显示位置—列高地址
        for (n = 0; n < 72; n++)
            OLED_WR_Byte(0, OLED_DATA);
    } // 更新显示
}
// 显示字符
inline void OLED_ShowChar(uint8_t x, uint8_t y, const uint8_t chr)
{
    uint8_t c = 0, temp;
    uint16_t i = 0, size1;
    c = chr - ' '; // 得到偏移后的值
    OLED_Set_Pos(x, y);
    for (i = 0; i < 6; i++)
    {
        temp = pgm_read_byte(&asc2_0806[c][i]);
        OLED_WR_Byte(temp, OLED_DATA); // 6X8字号
    }
}

void _display::begin()
{
    screen.setPins(SCREEN_SDA, SCREEN_SCL);
    screen.setClock(400000);
    screen.setBufferSize(512);
    screen.begin();

    OLED_WR_Byte(0xAE, OLED_CMD); /*display off*/
    OLED_WR_Byte(0xD5, OLED_CMD); /*set osc division*/
    OLED_WR_Byte(0xF0, OLED_CMD);
    OLED_WR_Byte(0xA8, OLED_CMD); /*multiplex ratio*/
    OLED_WR_Byte(0x27, OLED_CMD); /*duty = 1/40*/
    OLED_WR_Byte(0xD3, OLED_CMD); /*set display offset*/
    OLED_WR_Byte(0x00, OLED_CMD);
    OLED_WR_Byte(0x40, OLED_CMD); /*Set Display Start Line */
    OLED_WR_Byte(0x8d, OLED_CMD); /*set charge pump enable*/
    OLED_WR_Byte(0x14, OLED_CMD);
    OLED_WR_Byte(0x20, OLED_CMD); /*Set page address mode*/
    OLED_WR_Byte(0x02, OLED_CMD); /*PAGE ADDRESS*/
    OLED_WR_Byte(0xA1, OLED_CMD); /*set segment remap*/
    OLED_WR_Byte(0xC8, OLED_CMD); /*Com scan direction*/
    OLED_WR_Byte(0xDA, OLED_CMD); /*set COM pins*/
    OLED_WR_Byte(0x12, OLED_CMD);
    OLED_WR_Byte(0xAD, OLED_CMD); /*Internal IREF Setting*/
    OLED_WR_Byte(0x30, OLED_CMD);
    OLED_WR_Byte(0x81, OLED_CMD); /*contract control*/
    OLED_WR_Byte(0xfF, OLED_CMD); /*128*/
    OLED_WR_Byte(0xD9, OLED_CMD); /*set pre-charge period*/
    OLED_WR_Byte(0x22, OLED_CMD);
    OLED_WR_Byte(0xdb, OLED_CMD); /*set vcomh*/
    OLED_WR_Byte(0x20, OLED_CMD);
    OLED_WR_Byte(0xA4, OLED_CMD); /*Set Entire Display On/Off*/
    OLED_WR_Byte(0xA6, OLED_CMD); /*normal / reverse*/
    OLED_WR_Byte(0x0C, OLED_CMD); /*set lower column address*/
    OLED_WR_Byte(0x11, OLED_CMD); /*set higher column address*/
    OLED_Clear();
    OLED_WR_Byte(0xAF, OLED_CMD); /*display ON*/

    OLED_ColorTurn(0);   // 0正常显示 1反色显示
    OLED_DisplayTurn(0); // 0正常显示 1翻转180度显示

    display.init = true;
}

// 填充空间计算
inline uint32_t oled_pow(uint8_t m, uint8_t n)
{
    uint32_t result = 1;
    while (n--)
        result *= m;
    return result;
}

// 显示字符串
void _display::draw_strings(const char *chr, uint8_t x, uint8_t y)
{
    if (!init)
        return;
    if (millis() < update_screen)
        return;
    uint8_t j = 0;
    while (chr[j] != '\0')
    {
        OLED_ShowChar(x, y, chr[j++]);
        x += 6;
    }
}

// 显示数字
inline void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t size)
{
    uint8_t t, temp, m = 0;
    uint8_t enshow = 0;
    m = 2;
    for (t = 0; t < size; t++)
    {
        temp = (num / oled_pow(10, size - t - 1)) % 10;
        if (enshow == 0 && t < (size - 1))
        {
            if (temp == 0)
            {
                OLED_ShowChar(x + (4 + m) * t, y, ' ');
                continue;
            }
            else
                enshow = 1;
        }
        OLED_ShowChar(x + (4 + m) * t, y, temp + '0');
    }
}

// 显示UINT32
void _display::draw_uint32(uint32_t draw, uint8_t x, uint8_t y, uint8_t size)
{
    if (!init)
        return;
    if (millis() < update_screen)
        return;
    // OLED_Display_On();
    OLED_ShowNum(x, y, draw, size);
}

void _display::update(uint8_t clr)
{
    if (clr) {
        OLED_Clear();
    }
    else
    {
        if (millis() < update_screen)
            return;
        screen.beginTransmission(0x3c);
        for (uint16_t _buf = 0; _buf < _buffer_size; _buf++)
        {
            screen.write((uint8_t)_buffer[_buf]);
            _buffer[_buf] = 0;
        }
        _buffer_size = 0;
        screen.endTransmission();

        update_screen = millis() + 10U;
    }
}